
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

#include <linux/mod_devicetable.h>
#include <linux/of_device.h>

#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <asm/current.h>
#include <linux/delay.h>
#include <linux/version.h>
#include <linux/spi/spi.h>


#define  CMD   100
#define	 DATA  101

#define SET_DISP_LOC  0
#define WRITE_LEN_DATAS   1

static int major;
static struct class *oled_class;
static struct gpio_desc *oled_dc;
static unsigned char oled_data = 0;

static struct spi_device *oled_dev;




static int oled_open(struct inode *node, struct file *file)
{
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}



static int oled_close(struct inode *node, struct file *file)
{
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}


static int oled_write_cmd_data(unsigned char arg, int cmd_or_data)
{
	if (cmd_or_data == CMD)
	{
		gpiod_set_value(oled_dc, 0);
		
	}
	else
	{
		gpiod_set_value(oled_dc, 1);
	}
	
	spi_write(oled_dev, &arg, 1);
	return 0;
}


static void oled_write_datas(unsigned char *buf, int len)
{
	//*GPIO4_DR_s |= (1<<20);//拉高，表示写入数据
	gpiod_set_value(oled_dc, 1);
	// spi_writeread(ESCPI1_BASE,uc_data);//写入
	spi_write(oled_dev, buf, len);
}


//坐标设置
/**********************************************************************
	 * 函数名称： OLED_DIsp_Set_Pos
	 * 功能描述：设置要显示的位置
	 * 输入参数：@ x ：要显示的column address
	 			@y :要显示的page address
	 * 输出参数： 无
	 * 返 回 值： 
	 * 修改日期 	   版本号	 修改人		  修改内容
	 * -----------------------------------------------
	 * 2020/03/15		 V1.0	  芯晓		  创建
 ***********************************************************************/
void oled_disp_set_pos(int x, int y)
{ 	oled_write_cmd_data(0xb0+y, CMD);
	oled_write_cmd_data((x&0x0f), CMD); 
	oled_write_cmd_data(((x&0xf0)>>4)|0x10, CMD);
}   




static long oled_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
{
	unsigned char *user_buff = (unsigned char *)arg;
	unsigned char *kernel_buff;
	unsigned int len;
	
	switch(cmd & 0xff)
	{
		case SET_DISP_LOC:
		{
			copy_from_user(kernel_buff, user_buff, 2);
			oled_disp_set_pos(kernel_buff[0], kernel_buff[1]);
			break;
		}

		case WRITE_LEN_DATAS:
		{
			len = cmd >> 8;
			copy_from_user(kernel_buff, user_buff, len);
			oled_write_datas(kernel_buff, len);
			break;
		}
	}
	return 0;

}






/**********************************************************************
	 * 函数名称： oled_hardware_init
	 * 功能描述： oled_hardware_init的初始化，包括SPI控制器得初始化
	 * 输入参数：无
	 * 输出参数： 初始化的结果
	 * 返 回 值： 成功则返回0，否则返回-1
	 * 修改日期 	   版本号	 修改人		  修改内容
	 * -----------------------------------------------
	 * 2020/03/15		 V1.0	  芯晓		  创建
 ***********************************************************************/

static int oled_hardware_init(void)
{
	oled_write_cmd_data(0xae,CMD);//关闭显示

	oled_write_cmd_data(0x00,CMD);//设置 lower column address
	oled_write_cmd_data(0x10,CMD);//设置 higher column address

	oled_write_cmd_data(0x40,CMD);//设置 display start line

	oled_write_cmd_data(0xB0,CMD);//设置page address

	oled_write_cmd_data(0x81,CMD);// contract control
	oled_write_cmd_data(0x66,CMD);//128

	oled_write_cmd_data(0xa1,CMD);//设置 segment remap

	oled_write_cmd_data(0xa6,CMD);//normal /reverse

	oled_write_cmd_data(0xa8,CMD);//multiple ratio
	oled_write_cmd_data(0x3f,CMD);//duty = 1/64

	oled_write_cmd_data(0xc8,CMD);//com scan direction

	oled_write_cmd_data(0xd3,CMD);//set displat offset
	oled_write_cmd_data(0x00,CMD);//

	oled_write_cmd_data(0xd5,CMD);//set osc division
	oled_write_cmd_data(0x80,CMD);//

	oled_write_cmd_data(0xd9,CMD);//ser pre-charge period
	oled_write_cmd_data(0x1f,CMD);//

	oled_write_cmd_data(0xda,CMD);//set com pins
	oled_write_cmd_data(0x12,CMD);//

	oled_write_cmd_data(0xdb,CMD);//set vcomh
	oled_write_cmd_data(0x30,CMD);//

	oled_write_cmd_data(0x8d,CMD);//set charge pump disable 
	oled_write_cmd_data(0x14,CMD);//

	oled_write_cmd_data(0xaf,CMD);//set dispkay on

	return 0;
		  
}

/**********************************************************************
	 * 函数名称： OLED_DIsp_Clear
	 * 功能描述： 整个屏幕显示数据清0
	 * 输入参数：无
	 * 输出参数： 无
	 * 返 回 值： 
	 * 修改日期 	   版本号	 修改人		  修改内容
	 * -----------------------------------------------
	 * 2020/03/15		 V1.0	  芯晓		  创建
 ***********************************************************************/

static void oled_screen_clear(void)
{
	unsigned char x, y;
	for(y = 0; y < 8; y++)
	{
		oled_disp_set_pos(0, y);
		for(x = 0; x < 128; x++ )
			oled_write_cmd_data((y > 4) ? 0xff : 0, DATA);
	}
}

static struct file_operations oled_ops = {
	.owner  = THIS_MODULE,
	.open    = oled_open,
	.release = oled_close,
	.unlocked_ioctl = oled_ioctl,
};




static struct of_device_id of_match_table_oled[] = {
	{ .compatible = "oled,zmq", },
	{ },
};

static struct spi_device_id oled_table[] = {
	{"oled,zmq",},
	{},
};




static int oled_probe(struct spi_device *spi)
{
	
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);
	oled_dev = spi;

	major = register_chrdev(0, "zmq_oled_chrdev", &oled_ops);
	oled_class = class_create(THIS_MODULE, "oled_class_name");
	if(IS_ERR(oled_class))
	{
		unregister_chrdev(major, "zmq_oled_chrdev");
		return PTR_ERR(oled_class);
	}
	device_create(oled_class, NULL, MKDEV(major, 0), NULL, "oled_zmq");
	oled_dc = gpiod_get(&spi->dev, "dc", GPIOD_OUT_HIGH);

	oled_hardware_init();
	oled_screen_clear();
	return 0;
	
}

static int oled_remove(struct spi_device *spi)
{

	device_destroy(oled_class, MKDEV(major, 0));
	class_destroy(oled_class);
	unregister_chrdev(major, "zmq_oled_chrdev");
	gpiod_put(oled_dc);
	return 0;
}


static struct spi_driver oled_drv = {
	.probe = oled_probe,
	.remove = oled_remove,
	.driver = 	{
		.name = "oled",
		.of_match_table = of_match_table_oled,
	},

	.id_table = oled_table,
};



static int oled_init(void)
{
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);
	spi_register_driver(&oled_drv);
	
	return 0;
}


static void oled_exit(void)
{
	printk("%s %s  line %d\n", __FILE__, __FUNCTION__, __LINE__);

	spi_unregister_driver(&oled_drv);
}


module_init(oled_init);
module_exit(oled_exit);
MODULE_LICENSE("GPL");






